//
//  IRTCSDK.m
//  ivcs_ios_demo
//
//  Created by zealcomm user on 2020/10/24.
//  Copyright © 2020 zealcomm user. All rights reserved.
//

#import "IRTCSDK.h"
#import "Tool.h"
#import <IRTC/IRTC.h>
#import <IRTC/IRTCLocalCameraStream.h>
#import <objc/runtime.h>

static NSString *ivcsIrtcErrorDomain = @"zealcomm.ivcs.irtc";

@interface IRTCSDK()<IRTCConferenceClientDelegate,IRTCRemoteStreamDelegate>
/// irtc client
@property (strong, nonatomic) IRTCConferenceClient *conferenceClient;

@property(strong, nonatomic) IRTCLocalCameraStream *localStream;

@property (strong, nonatomic) IRTCShareScreenStream *shareStream;

@property(strong, nonatomic) IRTCConferencePublication *localPublication;
@property(strong, nonatomic) IRTCConferencePublication *localSharePublication;

@property(nonatomic, strong) NSMutableArray<IRTCRemoteStream*> *remoteStreams;

@property(nonatomic,strong)IRTCConferenceInfo *conferenceInfo;

@property BOOL usingFrontCamera;

@property(nonatomic, assign) CGSize resolution;

@property(nonatomic, assign) double frameRate;

@end

@implementation IRTCSDK

relizeSingleInstance()

-(void)joinRoomWithToken:(NSString *)token onSuccess:(void (^)(IRTCConferenceInfo * _Nonnull))success onFailure:(void (^)(NSError * _Nonnull))failure{
    [self.conferenceClient joinWithToken:token onSuccess:^(IRTCConferenceInfo * _Nonnull info) {
        self.labelAndStreams = [NSMutableDictionary dictionary];
        NSLog(@"info.remoteStreams ===== %@",info.remoteStreams);
        self.remoteStreams = [NSMutableArray arrayWithArray:info.remoteStreams];
        NSLog(@"info.remoteStreams ===== %ld",self.remoteStreams.count);
        for(IRTCRemoteStream *stream in info.remoteStreams){
            if (stream.source.video == IRTCVideoSourceInfoMixed) {
            }else{
                NSString *label = [[stream attributes]  objectForKey:@"type"];
                [stream setAttributes:@{@"type":label}];
                [self.labelAndStreams setObject:stream forKey:info.myself.role];
                [self.remoteStreams addObject:stream];
                stream.delegate = self;
                    
                NSDictionary *dic = @{
                    @"stream":stream,
                    @"label":info.myself.role
                };
                [[NSNotificationCenter defaultCenter]postNotificationName:@"AddNewStream" object:dic];
    
            }
        }
       
        self.conferenceInfo = info;
        self.participantId = info.myself.participantId;
        success(info);
        MyLog(@"irtc 加入房间成功");
    } onFailure:^(NSError * _Nonnull error) {
        MyLog(@"irtc 加入房间失败");
        failure(error);
    }];
}

-(void)publishLocalStreamToRoomWithStreamLabel:(NSString *)label mediaStreamSettingOptions:(MediaStreamSettingOptions *)options onSuccess:(void (^)(IRTCLocalCameraStream * _Nonnull, IRTCConferencePublication * _Nonnull))success onFailure:(void (^)(NSError * _Nonnull))failure{
    NSLog(@"start publish local stream with label,%@,%@",label,[Tool getCurrentTimes]);
    IRTCStreamConstraints *constraints = options.streamConstraints;
    IRTCPublishOptions *publishOptions = options.publishOptions;
    [self.localStream stop];
    [self.localPublication stop];
    @try {
        NSError *err= [NSError errorWithDomain:ivcsIrtcErrorDomain code:4000 userInfo:nil];
        self.localStream = [[IRTCLocalCameraStream alloc] initWithConstratins:constraints error:&err];
        [self.localStream setAttributes:@{@"type":label}];
        [self.conferenceClient publish:self.localStream withOptions:publishOptions onSuccess:^(IRTCConferencePublication * _Nonnull p) {
            NSLog(@"success publish local stream with label,%@,,%@,,%@",label,p,[Tool getCurrentTimes]);
            success(self.localStream,p);
            self.localPublication = p;
        } onFailure:^(NSError * _Nonnull error) {
            failure(error);
        }];
    } @catch (NSException *exception) {
        NSError *error = [[NSError alloc] initWithDomain:ivcsIrtcErrorDomain code:4006 userInfo:exception.userInfo];
        failure(error);
    } @finally {
        
    }
}
-(void)endShareStream{
    [self.shareStream stop];
    [self.localSharePublication stop];
}

-(void)publishShareStreamToRoomWithStreamLabel:(NSString *)label mediaStreamSettingOptions:(MediaStreamSettingOptions *)options onSuccess:(void (^)(IRTCLocalCameraStream * _Nonnull, IRTCConferencePublication * _Nonnull))success onFailure:(void (^)(NSError * _Nonnull))failure{
    NSLog(@"start publish local stream with label,%@,%@",label,[Tool getCurrentTimes]);
    IRTCPublishOptions *publishOptions = options.publishOptions;
    IRTCShareScreenConstraints* constraints = [[IRTCShareScreenConstraints alloc] init];
    constraints.audio = FALSE;
    constraints.video = TRUE;
    @try {
        [self.shareStream stop];
        [self.localSharePublication stop];
        NSError *err= [NSError errorWithDomain:ivcsIrtcErrorDomain code:4000 userInfo:nil];
        self.shareStream = [[IRTCShareScreenStream alloc] initWithConstratins:constraints error:&err];
        [self.shareStream setAttributes:@{@"type":label}];
        [self.conferenceClient publish:self.shareStream withOptions:publishOptions onSuccess:^(IRTCConferencePublication * _Nonnull p) {
            success(self.localStream,p);
            self.localSharePublication = p;
        } onFailure:^(NSError * _Nonnull error) {
            failure(error);
        }];
    } @catch (NSException *exception) {
        NSError *error = [[NSError alloc] initWithDomain:ivcsIrtcErrorDomain code:4006 userInfo:exception.userInfo];
        failure(error);
    } @finally {
        
    }
}

-(void)subscribeStreamWithLabel:(NSString *)label IRTCRemoteStream:(IRTCRemoteStream *)remoteStream onSuccess:(void (^)(IRTCConferenceSubscription * _Nonnull))success onFailure:(void (^)(NSError * _Nonnull))failure{
     MyLog(@"%@,subscribeStreamWithLabel,%@,%@",remoteStream.streamId,label,[Tool getCurrentTimes]);
     [self.conferenceClient subscribe:remoteStream withOptions:nil onSuccess:^(IRTCConferenceSubscription * _Nonnull subscription) {
                 success(subscription);
         } onFailure:^(NSError * _Nonnull error) {
                 failure(error);
     }];
}


- (IRTCConferenceClient*)conferenceClient{
    if (_conferenceClient==nil){
        IRTCConferenceClientConfiguration* config=[[IRTCConferenceClientConfiguration alloc]init];
        _conferenceClient=[[IRTCConferenceClient alloc]initWithConfiguration:config];
        _conferenceClient.delegate=self;
    }
    return _conferenceClient;
}

-(void)leaveRoomSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self.localPublication stop];
    MyLog(@"IRTCSDK:leave room start...");
    [self.conferenceClient leaveWithOnSuccess:^{
        MyLog(@"IRTCSDK:%@,leave room success",[Tool getCurrentTimes]);
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        MyLog(@"IRTCSDK:%@,leave room error,,%@",[Tool getCurrentTimes],error);
        onFailure(error);
    }];
}

-(void)muteWithMediaType:(IRTCTrackKind)type onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self.localPublication mute:type onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)unmuteWithMediaType:(IRTCTrackKind)type onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self.localPublication unmute:type onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

- (void)switchCameraOnSuccess:(nullable void (^)(void))onSuccess onFailure:(nullable void (^)(NSError * _Nonnull))onFailure{
    [self.localStream switchCameraOnSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

- (CGSize)getVideoSizeByVideoLabel:(NSString *)videoLabel{
    IRTCRemoteStream *stream = self.labelAndStreams[videoLabel];
    NSValue *value = stream.capabilities.video.resolutions[0];
    return [value CGSizeValue];
}

-(void)getSnapShotImage:(void (^)(UIImage*))onSuccess onFailure:(void (^)(NSError*))onFailure{
    [self.localStream capture:^(UIImage * _Nonnull image) {
        onSuccess(image);
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}
//
-(void)getCustomerSnapShotImage:(void (^)(UIImage*))onSuccess onFailure:(void (^)(NSError*))onFailure{
    IRTCRemoteStream *stream = self.labelAndStreams[@"customer"];
    [stream capture:^(UIImage * _Nonnull image) {
        onSuccess(image);
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
    
}

#pragma mark IRTCConferenceClientDelegate
/**
  @brief Triggers when client is disconnected from conference server.<br>当客户端和会议服务器断开连接时触发。
*/
- (void)conferenceClientDidDisconnect:(IRTCConferenceClient*)client{
    MyLog(@"%@,,%@,,conferenceClientDidDisconnect",client,[Tool getCurrentTimes]);
}
/**
  @brief Triggers when a stream is added.<br>当有新的媒体流加入时触发。
  @param stream The stream which is added.<br>新加入的媒体流。
*/
- (void)conferenceClient:(IRTCConferenceClient*)client
            didAddStream:(IRTCRemoteStream*)stream{
    NSLog(@"stream===%@ streamId===%@",stream.origin,stream.streamId);
    if ([stream.origin isEqualToString:self.participantId]) {
        MyLog(@"is my stream");
        return;
    }
    MyLog(@"收到了一个远程流");
    if (self.delegate && [self.delegate respondsToSelector:@selector(onStreamAddWithLabel:)]) {
        NSString *label = [stream.attributes valueForKey:@"type"];
        MyLog(@"远程流的 origin=%@ , streamId=%@" , stream.origin , stream.streamId);
        if (label == nil || [label isKindOfClass:[NSNull class]] || label.length == 0) {
            MyLog(@"这个是 ai 坐席流，videoLabel:%@" , self.lastAiAgentVideoLabel);
            label = self.lastAiAgentVideoLabel;
        }
        [stream setAttributes:@{@"type":label}];
        [self.labelAndStreams setObject:stream forKey:label];
        [self.delegate onStreamAddWithLabel:label];
    }
//    if ([stream.origin isEqualToString:self.participantId]) {
//        MyLog(@"is my stream");
//        return;
//    }
    [self.remoteStreams addObject:stream];
    stream.delegate = self;
}
/**
 @brief Triggers when a message is received.<br>当接收到新的消息时触发。
 @param senderId Sender's ID.<br>发送者的ID。
 @param message Message received.<br>接收到的消息。
 @param targetType "all" if broadcast message. "me"
 if the message is sent only to current conference client.<br>如果是"all"则是广播消息；如果是"me"则是指定发送目标的消息。
 */
- (void)conferenceClient:(IRTCConferenceClient*)client
       didReceiveMessage:(NSString*)message
                    from:(NSString*)senderId
                      to:(NSString*)targetType{
    
}
/**
 @brief Triggers when a user joined conference.<br>当有新的用户加入会议时触发。
 @param user The user joined.<br>新加入的用户。
 */
- (void)conferenceClient:(IRTCConferenceClient*)client
       didAddParticipant:(IRTCConferenceParticipant*)user{
    MyLog(@"%@,%@,didAddParticipant,,%@",client,[Tool getCurrentTimes],user.participantId);
}

#pragma mark IRTCRemoteStreamDelegate
/// conference.<br>当一条媒体流结束或者不再在会议内有效时触发。
- (void)streamDidEnd:(IRTCRemoteStream*)stream{
    MyLog(@"%@,%@,stream did end",stream.streamId,[Tool getCurrentTimes]);
    [self.remoteStreams enumerateObjectsUsingBlock:^(IRTCRemoteStream* obj, NSUInteger idx, BOOL *stop) {
        if ([obj.streamId isEqualToString:stream.streamId]) {
            *stop = YES;
            if (*stop == YES) {
                [self.remoteStreams removeObjectAtIndex:idx];
            }
        }
        if (*stop) {
            MyLog(@"now remotestreams is %@",self.remoteStreams);
        }
    }];
    NSString *label = [stream.attributes valueForKey:@"type"];
    if (label == NULL || label.length == 0) {
        for(NSString *key in self.labelAndStreams.allKeys){
            if (self.labelAndStreams[key] == stream) {
                label = key;
                break;
            }
        }
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(onStreamRemoveWithLabel:)]) {
        [self.delegate onStreamRemoveWithLabel:label];
    }
    [self.labelAndStreams removeObjectForKey:label];
    [self.remoteStreams removeObject:stream];
}

/// Triggered when a stream is updated.<br>当一条媒体流更新时触发。
- (void)streamDidUpdate:(IRTCRemoteStream*)stream{
    MyLog(@"%@,%@,stream did update",stream.streamId,[Tool getCurrentTimes]);
}

- (void)streamDidMute:(IRTCRemoteStream *)stream trackKind:(IRTCTrackKind)kind{
    
}

- (void)streamDidUnmute:(IRTCRemoteStream *)stream trackKind:(IRTCTrackKind)kind{
    
}
@end
